﻿using System;
using Maria.Common.Aspects;

namespace RG.Common
{
    /// <summary>
    /// Валидатор для DAO-классов.
    /// Пока ничего не делает, потому что AspectTask добавляет не-виртуальные методы в класс,
    /// из-за которых NHibernate не может создать прокси
    /// </summary>
    public class StringLengthValidatorDAO : Attribute
    {
        /// <summary>
        /// Минимальная длина строки
        /// </summary>
        public int MinLength { get; set; }
        /// <summary>
        /// Максимальная длина строки
        /// </summary>
        public int MaxLength { get; set; }
        
        /// <summary>
        /// Ограничиваем строку по максимальной длине
        /// </summary>
        /// <param name="maxLength">Максимальная длина строки</param>
        public StringLengthValidatorDAO(int maxLength)
        {
            MaxLength = maxLength;
            MinLength = 0;
        }
        /// <summary>
        /// Ограничиваем строку по минимальной и максимальной длине
        /// </summary>
        /// <param name="minLenth">Минимальная длина строки</param>
        /// <param name="maxLength">Максимальная длина строки</param>
        public StringLengthValidatorDAO( int minLenth, int maxLength)
        {
            MaxLength = maxLength;
            MinLength = minLenth;
        }
    }

    public class StringLengthValidator : GenericMethodWrapper
    {
        /// <summary>
        /// Минимальная длина строки
        /// </summary>
        public int MinLength { get; set; }
        /// <summary>
        /// Максимальная длина строки
        /// </summary>
        public int MaxLength { get; set; }
        
        /// <summary>
        /// Ограничиваем строку по максимальной длине
        /// </summary>
        /// <param name="maxLength">Максимальная длина строки</param>
        public StringLengthValidator(int maxLength)
        {
            MaxLength = maxLength;
            MinLength = 0;
        }
        /// <summary>
        /// Ограничиваем строку по минимальной и максимальной длине
        /// </summary>
        /// <param name="minLenth">Минимальная длина строки</param>
        /// <param name="maxLength">Максимальная длина строки</param>
        public StringLengthValidator( int minLenth, int maxLength)
        {
            MaxLength = maxLength;
            MinLength = minLenth;
        }

        new public static object OnInvoke(WrapperParameter[] AttributeParameters, object[] MethodParameters, InvokeOriginal Invoker, object WrappedInstance, RuntimeTypeHandle WrappedType, string WrappedMethod)
        {
            if (MethodParameters.Length == 1 && AttributeParameters.Length == 1)
            {
                var new_value = MethodParameters[0] as string;
                var param = AttributeParameters[0] as StringLengthValidator;
                if (new_value != null && param != null)
                {
                    if (new_value.Length < param.MinLength)
                        throw new ValidationException(string.Format("Строка [{0}] должна содержать не менее {1} символов!", new_value, param.MinLength), WrappedType, WrappedMethod);
                    if (new_value.Length > param.MaxLength)
                        throw new ValidationException(string.Format("Строка [{0}] не должна превышать {1} символов!", new_value, param.MaxLength), WrappedType, WrappedMethod);
                }
            }
            return Invoker(MethodParameters);
        }
    }

    public class ValidationException : Exception
    {
        private readonly string m_MethodName;
        private readonly RuntimeTypeHandle m_TypeHandle;

        public ValidationException(string message, RuntimeTypeHandle typeHandle, string methodName) : base(message)
        {
            m_MethodName = methodName;
            m_TypeHandle = typeHandle;
        }

        public override string Message
        {
            get { return string.Format("Validation fault: [{0}] at [{1}::{2}].", base.Message, Type.GetTypeFromHandle(m_TypeHandle), m_MethodName); }
        }
    }
}
